package com.yfbao.horizon.common;

import cn.hutool.core.date.DateUtil;
import com.github.benmanes.caffeine.cache.Cache;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 缓存使用统计
 * 设计要求：
 * 1、步，计算简单；
 * 2、队列不能过大，超过1000后默认LRU
 * 3、定期缓存统计量输出
 */
public class CacheStats {

    private static Map<String,StatDto> liveCacheMap =new ConcurrentHashMap<>();
    private static List<StatDto> moveCacheMap = Collections.synchronizedList(new ArrayList<StatDto>());

    private static ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
    private static Random random= new Random();

    private static AtomicInteger callTime = new AtomicInteger(0);
    private static TimeUnit LOCAL_TIMEUNIT= TimeUnit.SECONDS;

//    private static Queue<StatTask> task = new ConcurrentLinkedQueue<>();


    static {
        scheduler.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                if(!moveCacheMap.isEmpty()){
                    Iterator<StatDto> iterator = moveCacheMap.iterator();
                    StringBuilder builder = new StringBuilder();
                    builder.append("moveCache size:").append(moveCacheMap.size()).append(";");
                    while (iterator.hasNext()){
                        StatDto next = iterator.next();
                        builder.append("key:").append(next.getKey()).append(":").append(next.getReadTimes().get()).append(":").append(next.getLiveTime()/1000).append("s; ");
                        iterator.remove();
                    }
                    System.out.println(builder.toString());
                }

                if(!liveCacheMap.isEmpty()){
                    Set<Map.Entry<String, StatDto>> entries = liveCacheMap.entrySet();
                    Iterator<Map.Entry<String, StatDto>> iterator = entries.iterator();
                    StringBuilder builder = new StringBuilder();
                    builder.append("liveCache size:").append(liveCacheMap.size()).append(";");
                    while (iterator.hasNext()){
                        Map.Entry<String, StatDto> next = iterator.next();
                        StatDto value = next.getValue();
                        builder.append("key:").append(next.getKey()).append(":").append(value.getReadTimes().get()).append(":").append(DateUtil.formatDate(new Date(value.getCreateTime()))).append("; ");
                    }
                    System.out.println(builder.toString());
                }

            }

        },60,1*60, LOCAL_TIMEUNIT);
    }
            //统计对象大小：            ObjectSizeCalculator.getObjectSize(moveCacheMap);


    public static void totalStat(Cache cacheParm,String cacheName){
        final Cache cache =cacheParm;
        final String name = cacheName;

        scheduler.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                StringBuilder builder = new StringBuilder();
                builder.append(name+"命中率："+cache.stats().hitRate()).append(";");
                builder.append(name+"命中次数："+cache.stats().hitCount()).append(";");
                builder.append(name+"回收缓存数量："+cache.stats().evictionCount()).append(";");
                builder.append(name+"回收缓存权重："+cache.stats().evictionWeight()).append(";");
                builder.append(name+"平均加载耗时："+cache.stats().averageLoadPenalty()).append(";");
                System.out.println(builder.toString());
            }
        },60+random.nextInt(10),2*60, LOCAL_TIMEUNIT);
    }


    public static void creatOrUpdCacheStat(String key){
        StatDto statDto = liveCacheMap.get(key);
        if(statDto ==null){
            statDto = new StatDto();
            statDto.setKey(key);
            liveCacheMap.put(key,statDto);
        }
        statDto.getUpdateTimes().incrementAndGet();
        int calls = callTime.incrementAndGet();
        if(calls>1000){
            callTime = new AtomicInteger(0);
            //触发动作 自动LRU
        }
    }

    public static void readCacheStat(String key){
        StatDto statDto = liveCacheMap.get(key);
        if(statDto ==null){
            return;
        }
        statDto.getReadTimes().incrementAndGet();
    }

    public static void moveCacheStat(String key){
        StatDto statDto = liveCacheMap.remove(key);
        if(statDto ==null){
            return;
        }
        statDto.setLiveTime(System.currentTimeMillis()-statDto.getCreateTime());
        moveCacheMap.add(statDto);
    }

//    public static void updateCacheStat(String key){
//        task.add(new StatTask("c",key));
//    }
//
//    public static void getCacheStat(String key){
//        task.add(new StatTask("r",key));
//    }
//
//    public static void deleteCacheStat(String key){
//        task.add(new StatTask("d",key));
//    }
//    private void doTaskQueue(){
//        if(task.isEmpty()){
//            return;
//        }
//        //定时线程执行 或者数量触发执行
//        StatTask poll = task.poll();
//        if(poll.getMethod().equalsIgnoreCase("c")){
//            creatCacheStat(poll.getValue());
//        }else if(poll.getMethod().equalsIgnoreCase("r")){
//            readCacheStat(poll.getValue());
//        }else if(poll.getMethod().equalsIgnoreCase("d")) {
//            moveCacheStat(poll.getValue());
//        }
//    }
//
//
//    static class StatTask{
//        public String getMethod() {
//            return method;
//        }
//
//        private String method;
//
//        public String getValue() {
//            return value;
//        }
//
//        private String value;
//        StatTask(String method,String value){
//            this.method=method;
//            this.value=value;
//        }
//    }






}
